package com.techzhi.tidb.loader;


import com.techzhi.tidb.config.TiDBConfigManager;
import com.techzhi.tidb.pool.TiDBConnectionPoolManager;
import com.techzhi.tidb.utils.TiDBOperationUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.EventListener;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * TiDB工具类动态加载器
 * 根据配置动态初始化TiDB相关组件
 *
 * @author shouzhi
 * @date 2025-09-01
 */

@Slf4j
public class TiDBUtilsLoader {

    @Autowired
    private TiDBConfigManager configManager;

    @Autowired
    private ApplicationContext applicationContext;

    private final AtomicBoolean loaded = new AtomicBoolean(false);
    private final AtomicBoolean loading = new AtomicBoolean(false);
    private final Object loadLock = new Object();

    /**
     * 动态加载TiDB工具类
     */
    public void loadTiDBUtils() {
        if (loaded.get()) {
            log.debug("TiDB工具类已加载，跳过重复加载");
            return;
        }

        if (loading.get()) {
            log.debug("TiDB工具类正在加载中，等待完成");
            synchronized (loadLock) {
                // TODO 等待加载完成
                return;
            }
        }

        synchronized (loadLock) {
            if (loaded.get()) {
                return;
            }

            if (!configManager.isEnabled()) {
                log.info("TiDB未启用 (tidb.enabled=false)，跳过工具类加载");
                return;
            }

            loading.set(true);

            try {
                log.info("开始动态加载TiDB工具类...");

                // 1. 验证配置
                validateConfiguration();

                // 2. 验证JDBC驱动
                validateJdbcDriver();

                // 3. 初始化连接池
                initializeConnectionPool();

                // 4. 注册工具类组件
                registerUtilsComponents();

                // 5. 执行健康检查
                performHealthCheck();

                loaded.set(true);
                log.info("TiDB工具类动态加载完成: {}", configManager.getMaskedConnectionInfo());

            } catch (Exception e) {
                log.error("TiDB工具类动态加载失败: {}", configManager.getMaskedConnectionInfo(), e);
                throw new RuntimeException("TiDB工具类动态加载失败", e);
            } finally {
                loading.set(false);
            }
        }
    }

    /**
     * 验证配置
     */
    private void validateConfiguration() {
        log.debug("验证TiDB配置...");

        if (!configManager.validateConfig()) {
            throw new IllegalStateException("TiDB配置验证失败，请检查配置参数");
        }

        // 验证连接池配置
        TiDBConfigManager.PoolConfig poolConfig = configManager.getPool();
        if (poolConfig.getMaximumPoolSize() <= 0) {
            throw new IllegalStateException("连接池最大连接数必须大于0");
        }

        if (poolConfig.getMinimumIdle() < 0) {
            throw new IllegalStateException("连接池最小空闲连接数不能小于0");
        }

        if (poolConfig.getMinimumIdle() > poolConfig.getMaximumPoolSize()) {
            throw new IllegalStateException("连接池最小空闲连接数不能大于最大连接数");
        }

        log.debug("TiDB配置验证通过");
    }

    /**
     * 验证JDBC驱动
     */
    private void validateJdbcDriver() {
        log.debug("验证MySQL JDBC驱动...");

        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            log.debug("MySQL JDBC驱动验证通过");
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException("MySQL JDBC驱动未找到，请确保已添加mysql-connector-java依赖", e);
        }
    }

    /**
     * 初始化连接池
     */
    private void initializeConnectionPool() {
        log.debug("初始化TiDB连接池...");

        try {
            TiDBConnectionPoolManager poolManager = applicationContext.getBean(TiDBConnectionPoolManager.class);
            poolManager.getDataSource(); // 触发初始化

            if (!poolManager.isInitialized()) {
                throw new RuntimeException("连接池初始化失败");
            }

            log.debug("TiDB连接池初始化完成");
        } catch (Exception e) {
            throw new RuntimeException("TiDB连接池初始化失败", e);
        }
    }

    /**
     * 注册工具类组件
     */
    private void registerUtilsComponents() {
        log.debug("注册TiDB工具类组件...");

        // 验证必要的Bean是否存在
        if (!applicationContext.containsBean("tiDBOperationUtils")) {
            throw new RuntimeException("TiDBOperationUtils组件未找到");
        }

        log.debug("TiDB工具类组件注册完成");
    }

    /**
     * 执行健康检查
     */
    private void performHealthCheck() {
        log.debug("执行TiDB健康检查...");

        try {
            TiDBOperationUtils operationUtils = applicationContext.getBean(TiDBOperationUtils.class);

            if (!operationUtils.testConnection()) {
                throw new RuntimeException("TiDB连接健康检查失败");
            }

            // 获取数据库版本信息
            String version = operationUtils.getDatabaseVersion();
            log.info("TiDB连接健康检查通过，数据库版本: {}", version);

        } catch (Exception e) {
            throw new RuntimeException("TiDB健康检查失败", e);
        }
    }

    /**
     * 获取加载状态
     */
    public boolean isLoaded() {
        return loaded.get();
    }

    /**
     * 获取加载中状态
     */
    public boolean isLoading() {
        return loading.get();
    }

    /**
     * 重新加载
     */
    public void reload() {
        log.info("开始重新加载TiDB工具类...");

        // 重置状态
        loaded.set(false);

        // 关闭现有连接池
        try {
            if (applicationContext.containsBean("tiDBConnectionPoolManager")) {
                TiDBConnectionPoolManager poolManager = applicationContext.getBean(TiDBConnectionPoolManager.class);
                poolManager.shutdown();
            }
        } catch (Exception e) {
            log.warn("关闭现有TiDB连接池时出现异常", e);
        }

        // 重新加载
        loadTiDBUtils();

        log.info("TiDB工具类重新加载完成");
    }

    /**
     * 强制卸载
     */
    public void unload() {
        log.info("开始卸载TiDB工具类...");

        synchronized (loadLock) {
            try {
                // 关闭连接池
                if (applicationContext.containsBean("tiDBConnectionPoolManager")) {
                    TiDBConnectionPoolManager poolManager = applicationContext.getBean(TiDBConnectionPoolManager.class);
                    poolManager.shutdown();
                }

                loaded.set(false);
                log.info("TiDB工具类卸载完成");

            } catch (Exception e) {
                log.error("TiDB工具类卸载失败", e);
            }
        }
    }

    /**
     * 获取加载状态信息
     */
    public LoadStatus getLoadStatus() {
        LoadStatus status = new LoadStatus();
        status.setLoaded(loaded.get());
        status.setLoading(loading.get());
        status.setEnabled(configManager.isEnabled());
        status.setConfigValid(configManager.validateConfig());

        if (loaded.get()) {
            try {
                TiDBConnectionPoolManager poolManager = applicationContext.getBean(TiDBConnectionPoolManager.class);
                status.setPoolInitialized(poolManager.isInitialized());
                status.setPoolHealthy(poolManager.isHealthy());
            } catch (Exception e) {
                status.setPoolInitialized(false);
                status.setPoolHealthy(false);
            }
        }

        return status;
    }

    /**
     * 应用启动后自动加载
     */
    @EventListener(ApplicationReadyEvent.class)
    public void onApplicationReady() {
        if (configManager.isEnabled()) {
            log.info("应用启动完成，开始自动加载TiDB工具类");
            try {
                loadTiDBUtils();
            } catch (Exception e) {
                log.error("应用启动时TiDB工具类自动加载失败", e);
                // 不抛出异常，避免影响应用启动
            }
        } else {
            log.info("TiDB未启用，跳过自动加载");
        }
    }

    /**
     * 加载状态信息类
     */
    public static class LoadStatus {
        private boolean loaded;
        private boolean loading;
        private boolean enabled;
        private boolean configValid;
        private boolean poolInitialized;
        private boolean poolHealthy;

        // getters and setters
        public boolean isLoaded() {
            return loaded;
        }

        public void setLoaded(boolean loaded) {
            this.loaded = loaded;
        }

        public boolean isLoading() {
            return loading;
        }

        public void setLoading(boolean loading) {
            this.loading = loading;
        }

        public boolean isEnabled() {
            return enabled;
        }

        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }

        public boolean isConfigValid() {
            return configValid;
        }

        public void setConfigValid(boolean configValid) {
            this.configValid = configValid;
        }

        public boolean isPoolInitialized() {
            return poolInitialized;
        }

        public void setPoolInitialized(boolean poolInitialized) {
            this.poolInitialized = poolInitialized;
        }

        public boolean isPoolHealthy() {
            return poolHealthy;
        }

        public void setPoolHealthy(boolean poolHealthy) {
            this.poolHealthy = poolHealthy;
        }
    }
}
